import { GeoUtils, Point } from "../../Engine";
import { BufferGeometry, CircleGeometry, DoubleSide, KeepStencilOp, Mesh, MeshBasicMaterial, NotEqualStencilFunc, Object3D, ReplaceStencilOp, Vector2, ZeroStencilOp} from "three";
import Const from "../../application/constants/Const";
import GeometryUtil from "../../renderExtension/utils/GeometryUtil";
import WidthLineGeometry from "../../renderExtension/geometriy/WidthLineGeometry";
/**
 * 线组件。该线条组件由多个矩形和多个圆组成，圆用于拐角处避免线条断裂。
 */
export default class LineWithWidth extends Object3D {
    private param: {pointArray: Array<Point>, color?: string, opacity?: number, lineWidth: number};
    private geoPointArray:{rectangleList: Array<Array<Vector2>>, circleList: Array<{center: Vector2, radius: number}>};
    
    public constructor(param: {pointArray: Array<Point>, color?: string, opacity?: number, lineWidth: number}){
        super();
        this.init(param);
    }

    private init(param){
        this.geoPointArray = {rectangleList: [], circleList: []};

        this.param = param;
        this.param.pointArray.forEach(element => {
            element.toEPSGWeb();
        });

        let firstLineCosSin = GeometryUtil.computeCosSin(this.param.pointArray[0], this.param.pointArray[1]);
        let newStartPoint = GeometryUtil.getNewPoint(this.param.pointArray[0], this.param.pointArray[1], param.lineWidth, firstLineCosSin);
        
        let length = this.param.pointArray.length;
        let endLineCosSin = GeometryUtil.computeCosSin(this.param.pointArray[length - 1], this.param.pointArray[length - 2]);
        let newEndPoint = GeometryUtil.getNewPoint(this.param.pointArray[length - 1], this.param.pointArray[length - 2], param.lineWidth, endLineCosSin);

        this.param.pointArray.unshift(new Point(newStartPoint.x, newStartPoint.y, newStartPoint.z, Const.EPSGType.EPSGWeb));
        this.param.pointArray.push(new Point(newEndPoint.x, newEndPoint.y, newEndPoint.z, Const.EPSGType.EPSGWeb));
        
        let firstPoint = this.param.pointArray[0];
        let currentPoint;
        let nextPoint;
        for (let i = 0; i < this.param.pointArray.length - 1; i++) {
            currentPoint = this.param.pointArray[i];
            currentPoint.z = firstPoint.z;

            nextPoint = this.param.pointArray[i + 1];
            nextPoint.z = firstPoint.z;

            let geometry: BufferGeometry = new WidthLineGeometry(currentPoint.clone(), nextPoint.clone(), param.lineWidth, currentPoint.clone());
            let material = new MeshBasicMaterial({
                color: param.color || '#0000CD',
                side: DoubleSide,
                depthTest: false,
                opacity: param.opacity,//覆盖物填充色透明
                transparent: true,

                stencilWrite: true,
				stencilRef: Const.StencilRefValue.LineWidthRef,
                stencilFuncMask: 0xff,
				stencilFunc: NotEqualStencilFunc,
				stencilFail: KeepStencilOp,
				stencilZFail: KeepStencilOp,
				stencilZPass: ReplaceStencilOp,
            });
            let planeMesh = new Mesh(geometry, material);
            planeMesh.renderOrder = -11;
            planeMesh.position.copy(currentPoint);
            this.add(planeMesh);

            let planePoints: Array<Vector2> = geometry['pointArray'];
            planePoints.forEach(element => {
                element.add(currentPoint);
            });
            this.geoPointArray.rectangleList.push(planePoints);

            if (i >= 2 && i < this.param.pointArray.length - 2) {//这样做是为了只在拐角处画圆
                this.createCircle(currentPoint);
                this.geoPointArray.circleList.push({center: new Vector2(currentPoint.x, currentPoint.y), radius: this.param.lineWidth});
            }
        }
    }

    private createCircle(circleCenter: Point) {
        let material = new MeshBasicMaterial({ 
            color: this.param.color,
            depthTest: false,
            opacity: this.param.opacity,//覆盖物填充色透明
            transparent: true,

            stencilWrite: true,
			stencilRef: Const.StencilRefValue.LineWidthRef,
            stencilFuncMask: 0xff,
			stencilFunc: NotEqualStencilFunc,
			stencilFail: KeepStencilOp,
			stencilZFail: KeepStencilOp,
			stencilZPass: ZeroStencilOp,
         });
        let geo  = new CircleGeometry(this.param.lineWidth, 50);    
        let circle = new Mesh(geo,material);
        circle.position.set(circleCenter.x, circleCenter.y, circleCenter.z);

        circle.visible = true;
        circle.renderOrder = -10;
        this.add(circle);
    }

    /**
     * 返回构成直线的各个几何体的顶点数组
     * @returns 
     */
    public getGeoPointArray() {
        return this.geoPointArray;
    }
}